﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace FastDFS.Client
{
    public class FastDFSClient
    {

        public static int DOWNLOAD_BUFFSIZE =1024;

        public static StorageNode GetStorageNode()
        {
            FDFSRequest trackerRequest = QUERY_STORE_WITH_GROUP_ONE.Instance.GetRequest();
            QUERY_STORE_WITH_GROUP_ONE.Response trackerResponse = new QUERY_STORE_WITH_GROUP_ONE.Response(trackerRequest.GetResponse());
            IPEndPoint storeEndPoint = new IPEndPoint(IPAddress.Parse(trackerResponse.IPStr), trackerResponse.Port);
            StorageNode result = new StorageNode
            {
                GroupName = trackerResponse.GroupName,
                EndPoint = storeEndPoint,
                StorePathIndex = trackerResponse.StorePathIndex
            };
            return result;
        }

        /// <summary>
        /// 获取存储节点
        /// </summary>
        /// <param name="groupName">组名</param>
        /// <returns>存储节点实体类</returns>
        public static StorageNode GetStorageNode(string groupName)
        {
            FDFSRequest trackerRequest = QUERY_STORE_WITH_GROUP_ONE.Instance.GetRequest(groupName);
            QUERY_STORE_WITH_GROUP_ONE.Response trackerResponse = new QUERY_STORE_WITH_GROUP_ONE.Response(trackerRequest.GetResponse());
            IPEndPoint storeEndPoint = new IPEndPoint(IPAddress.Parse(trackerResponse.IPStr), trackerResponse.Port);
            StorageNode result = new StorageNode
            {
                GroupName = trackerResponse.GroupName,
                EndPoint = storeEndPoint,
                StorePathIndex = trackerResponse.StorePathIndex
            };
            return result;
        }
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="storageNode">GetStorageNode方法返回的存储节点</param>
        /// <param name="contentByte">文件内容</param>
        /// <param name="fileExt">文件扩展名(注意:不包含".")</param>
        /// <returns>文件名</returns>
        public static string UploadFile(StorageNode storageNode,byte[] contentByte,string fileExt)
        {
            FDFSRequest storageReqeust = UPLOAD_FILE.Instance.GetRequest(storageNode.EndPoint, storageNode.StorePathIndex, contentByte.Length, fileExt, contentByte);
            UPLOAD_FILE.Response storageResponse = new UPLOAD_FILE.Response(storageReqeust.GetResponse());
            return storageResponse.FileName;
        }

        public static string UploadFile(StorageNode storageNode, FileStream fileStream, string fileExt)
        {
            byte[] content;
            using (BinaryReader reader = new BinaryReader(fileStream))
            {
                 content = reader.ReadBytes((int)fileStream.Length);
            }
            return UploadFile(storageNode, content, fileExt);
        }

        public static string[] UploadFile(StorageNode storageNode, params string[] fileNames)
        {
            string[] fdfsnames = new string[fileNames.Length];
            for (int i = 0; i < fileNames.Length; i++)
            {
                string fileName = fileNames[i],ext=Path.GetExtension(fileName).TrimStart('.');
                using (FileStream fileStream = new FileStream(fileName, FileMode.Open))
                {
                    fdfsnames[i] = UploadFile(storageNode, fileStream, ext);
                }
            }
            return fdfsnames;
        }

        /// <summary>
        /// 上传从文件
        /// </summary>
        /// <param name="storageNode">GetStorageNode方法返回的存储节点</param>
        /// <param name="contentByte">文件内容</param>
        /// <param name="master_filename">主文件名</param>
        /// <param name="prefix_name">从文件后缀</param>
        /// <param name="fileExt">文件扩展名(注意:不包含".")</param>
        /// <returns>文件名</returns>
        public static string UploadSlaveFile(string groupName, byte[] contentByte, string master_fdfsname, string prefix_name, string fileExt)
        {
            FDFSRequest trackerRequest = QUERY_UPDATE.Instance.GetRequest(groupName, master_fdfsname);
            QUERY_UPDATE.Response trackerResponse = new QUERY_UPDATE.Response(trackerRequest.GetResponse());
            IPEndPoint storeEndPoint = new IPEndPoint(IPAddress.Parse(trackerResponse.IPStr), trackerResponse.Port);

            FDFSRequest storageReqeust = UPLOAD_SLAVE_FILE.Instance.GetRequest(storeEndPoint, contentByte.Length, master_fdfsname, prefix_name, fileExt, contentByte);
            UPLOAD_FILE.Response storageResponse = new UPLOAD_FILE.Response(storageReqeust.GetResponse());
            return storageResponse.FileName;
        }

        public static string UploadSlaveFile(string groupName, FileStream fileStream, string master_fdfsname, string prefix_name, string fileExt)
        {
            byte[] content;
            using (BinaryReader reader = new BinaryReader(fileStream))
            {
                content = reader.ReadBytes((int)fileStream.Length);
            }
            return UploadSlaveFile(groupName, content, master_fdfsname, prefix_name, fileExt);
        }


        /// <summary>
        /// 上传可以Append的文件
        /// </summary>
        /// <param name="storageNode">GetStorageNode方法返回的存储节点</param>
        /// <param name="contentByte">文件内容</param>
        /// <param name="fileExt">文件扩展名(注意:不包含".")</param>
        /// <returns>文件名</returns>
        public static string UploadAppenderFile(StorageNode storageNode, byte[] contentByte, string fileExt)
        {
            FDFSRequest storageReqeust = UPLOAD_APPEND_FILE.Instance.GetRequest(storageNode.EndPoint, storageNode.StorePathIndex, contentByte.Length, fileExt, contentByte);
            UPLOAD_APPEND_FILE.Response storageResponse = new UPLOAD_APPEND_FILE.Response(storageReqeust.GetResponse());
            return storageResponse.FileName;
        }
        /// <summary>
        /// 附加文件
        /// </summary>
        /// <param name="groupName">组名</param>
        /// <param name="fileName">文件名</param>
        /// <param name="contentByte">文件内容</param>
        public static int AppendFile(string groupName, string fdfsName, byte[] contentByte)
        {
            int eff = 0;
            FDFSRequest trackerRequest = QUERY_UPDATE.Instance.GetRequest(groupName, fdfsName);
            QUERY_UPDATE.Response trackerResponse = new QUERY_UPDATE.Response(trackerRequest.GetResponse());
            IPEndPoint storeEndPoint = new IPEndPoint(IPAddress.Parse(trackerResponse.IPStr), trackerResponse.Port);

            FDFSRequest storageReqeust = APPEND_FILE.Instance.GetRequest(storeEndPoint, fdfsName, contentByte);
            storageReqeust.GetResponse();
            eff++;
            return eff;
        }

        public static int AppendFile(string groupName, string fdfsName, FileStream fileStream)
        {
            byte[] content;
            using (BinaryReader reader = new BinaryReader(fileStream))
            {
                content = reader.ReadBytes((int)fileStream.Length);
            }
            return AppendFile(groupName,fdfsName,content);
        }

        public static int AppendFile(string groupName, string fdfsName, params string[] fileNames)
        {
            int eff = 0;
            for (int i = 0; i < fileNames.Length; i++)
            {
                string fileName = fileNames[i], ext = Path.GetExtension(fileName).TrimStart('.');
                using (FileStream fileStream = new FileStream(fileName, FileMode.Open))
                {
                    eff+=AppendFile(groupName, fdfsName, fileStream);
                }
            }
            return eff;
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="groupName">组名</param>
        /// <param name="fileName">文件名</param>
        public static void RemoveFile(string groupName, string fdfsName)
        {
            FDFSRequest trackerRequest = QUERY_UPDATE.Instance.GetRequest(groupName, fdfsName);
            QUERY_UPDATE.Response trackerResponse = new QUERY_UPDATE.Response(trackerRequest.GetResponse());
            IPEndPoint storeEndPoint = new IPEndPoint(IPAddress.Parse(trackerResponse.IPStr), trackerResponse.Port);
            FDFSRequest storageReqeust = DELETE_FILE.Instance.GetRequest(storeEndPoint, groupName, fdfsName);
            storageReqeust.GetResponse();
        }

        public static string RemoveSlaveFile(string groupName, string masterFdfsName,string prefix)
        {
            string fdfsName = GenSlaveFDFSName(masterFdfsName, prefix);
            RemoveFile(groupName, fdfsName);
            return fdfsName;
        }

        public static int DownloadAndSave(StorageNode storageNode)
        {
            return 0;
        }

        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="storageNode">GetStorageNode方法返回的存储节点</param>
        /// <param name="fileName">文件名</param>
        /// <returns>文件内容</returns>
        public static byte[] DownloadFile(StorageNode storageNode, string fdfsName)
        {
            return DownloadFile(storageNode, fdfsName, 0L, 0L);
        }
        /// <summary>
        /// 增量下载文件
        /// </summary>
        /// <param name="storageNode">GetStorageNode方法返回的存储节点</param>
        /// <param name="fileName">文件名</param>
        /// <param name="offset">从文件起始点的偏移量</param>
        /// <param name="length">要读取的字节数</param>
        /// <returns>文件内容</returns>
        public static byte[] DownloadFile(StorageNode storageNode, string fdfsName, long offset, long length)
        {
            FDFSRequest storageReqeust = DOWNLOAD_FILE.Instance.GetRequest(storageNode.EndPoint, offset, length, storageNode.GroupName, fdfsName);
            DOWNLOAD_FILE.Response storageResponse = new DOWNLOAD_FILE.Response(storageReqeust.GetResponse());
            return storageResponse.Content;
        }

        public static int DowloadAndSaveFile(StorageNode storageNode, string fdfsName,params string[] saveFileNames)
        {
            FDFSFileInfo fileInfo = GetFileInfo(storageNode, fdfsName);
            byte[] buffer;
            int eff = 0;
            foreach (var saveFileName in saveFileNames)
            {
                using (FileStream fs = new FileStream(saveFileName, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    if (fileInfo.FileSize > DOWNLOAD_BUFFSIZE)
                    {
                        for (long offset = 0, len = DOWNLOAD_BUFFSIZE; len > 0;)
                        {
                            buffer = DownloadFile(storageNode, fdfsName, offset, len);
                            fs.Write(buffer, 0, buffer.Length);
                            fs.Flush();
                            offset += len;
                            long diff = fileInfo.FileSize - offset;
                            if (diff < DOWNLOAD_BUFFSIZE) len = diff;
                        }
                    }
                    else
                    {
                        buffer =DownloadFile(storageNode, fdfsName);
                        fs.Write(buffer, 0, buffer.Length);
                        fs.Flush();
                    }

                    eff++;

                }
            }
            return eff;


        }

        

        /// <summary>
        /// 获取文件信息
        /// </summary>
        /// <param name="storageNode">GetStorageNode方法返回的存储节点</param>
        /// <param name="fileName">文件名</param>
        /// <returns></returns>
        public static FDFSFileInfo GetFileInfo(StorageNode storageNode, string fdfsName)
        {
            FDFSRequest storageReqeust = QUERY_FILE_INFO.Instance.GetRequest(storageNode.EndPoint, storageNode.GroupName, fdfsName);
            FDFSFileInfo result = new FDFSFileInfo(storageReqeust.GetResponse())
            {
                FdfsName = fdfsName
            };
            return result;
        }

        public static FDFSFileInfo GetSlaveFileInfo(StorageNode storageNode, string masterFdfsName,string prefix)
        {
            string fdfsName = GenSlaveFDFSName(masterFdfsName, prefix);
            return GetFileInfo(storageNode, fdfsName);
        }


        public static string GenSlaveFDFSName(string masterFdfsName, string prefix)
        {
            string key = masterFdfsName.Substring(0, masterFdfsName.LastIndexOf("."));
            string ext = Path.GetExtension(masterFdfsName);
            return key+prefix+ext;
        }
    }
}
